package org.study.redis.boot.config;

import cn.hutool.core.util.ObjectUtil;
import io.protostuff.*;
import io.protostuff.runtime.RuntimeSchema;
import lombok.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

/**
 * 自定义 ProtoStuff 序列化器
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2025年02月16日
 */
public class ProtoStuffRedisSerializer implements RedisSerializer<Object> {
    private final Schema<BytesWrapper> schema;

    public ProtoStuffRedisSerializer() {
        this.schema = RuntimeSchema.getSchema(BytesWrapper.class);
    }

    @Override
    public byte[] serialize(Object object) throws SerializationException {
        if (object == null) {
            return null;
        }
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            return ProtobufIOUtil.toByteArray(new BytesWrapper<>(object), schema, buffer);
        } finally {
            buffer.clear();
        }
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if (ObjectUtil.isEmpty(bytes)) {
            return null;
        }
        BytesWrapper<Object> wrapper = new BytesWrapper<>();
        ProtobufIOUtil.mergeFrom(bytes, wrapper, schema);
        return wrapper.getValue();
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class BytesWrapper<T> implements Cloneable {
        private T value;

        @SuppressWarnings("unchecked")
        @Override
        public BytesWrapper<T> clone() {
            try {
                return (BytesWrapper<T>) super.clone();
            } catch (CloneNotSupportedException e) {
                return new BytesWrapper<T>();
            }
        }
    }
}
